﻿#pragma once
#ifndef VF_TCPCLIENT_H
#define VF_TCPCLIENT_H

#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>

namespace VFAdapter {

enum class MessageType : int {
  Select = 0, // 用于筛选
  GetMousePoint,
};

//!
//! @brief 消息接口
//!
//!
struct IMessage {
public:
  virtual std::string ToJson() const = 0;
  virtual MessageType GetMessageType() const = 0;
};

//!
//! @brief 选择筛选参数
//!
//!
struct SelFilterArg : public IMessage {
public:
  SelFilterArg();
  SelFilterArg(int filterType, std::string_view promptStr, bool isSingleSelect);

  //!
  //! @brief 序列化
  //!
  //! @return std::string
  //!
  std::string ToJson() const override;
  MessageType GetMessageType() const override { return MessageType::Select; }

private:
  int m_filterType;        // 筛选类型
  std::string m_promptStr; // 要给用户的提示
  bool m_isSingleSelect;   // 是否单选
};

struct GetMousePointArg : public IMessage {

public:
  MessageType GetMessageType() const override {
    return MessageType::GetMousePoint;
  }

  std::string ToJson() const override;

  GetMousePointArg();
  explicit GetMousePointArg(int64_t faceId);
  explicit GetMousePointArg(int64_t faceId, int64_t pointNum);

private:
  // 目标面
  int64_t m_faceId;
  // 想要在此面上取得点的个数
  int64_t m_pointNum = 1;
};

struct GetMousePointReturnData {
  uint32_t ErrorCode; // 错误码
  std::vector<double> X;
  std::vector<double> Y;
  std::vector<double> Z;

public:
  //!
  //! @brief 反序列化
  //!
  //! @param json
  //! @return GetMousePointReturnData
  //!
  static GetMousePointReturnData FromJson(const std::string &json);
};

//!
//! @brief 返回数据
//!
//!
struct SelReturnData {
  uint32_t errCode; // 错误码
  std::vector<int64_t> ElementIds;

public:
  //!
  //! @brief 反序列化
  //!
  //! @param json
  //! @return SelReturnData
  //!
  static SelReturnData FromJson(const std::string &json);
};

class MyTcpClient : public boost::enable_shared_from_this<MyTcpClient>,
                    boost::noncopyable {

private:
  MyTcpClient(std::string const &msg, SelReturnData *pRtData);
  typedef boost::system::error_code error_code;
  typedef boost::shared_ptr<MyTcpClient> ptr;
  //!
  //! @brief 连接端口
  //!
  //! @param ep
  //!
  void Connect(boost::asio::ip::tcp::endpoint const &ep);
  //!
  //! @brief 连接后处理
  //!
  //! @param ec
  //!
  void ConnectHandler(error_code const &ec);

  //!
  //! @brief 停止连接
  //!
  //!
  void Stop();

private:
  //!
  //! @brief 开始发送请求
  //!
  //!
  void StartSend();

  //!
  //! @brief 请求发送完毕后处理
  //!
  //! @param ec
  //!
  void SendHandler(error_code const &ec);

  //!
  //! @brief 开始接受响应
  //!
  //!
  void StartReceive();

  //!
  //! @brief 接受响应后处理
  //!
  //! @param ec
  void ReceiveHandler(error_code const &ec);

private:
  boost::asio::io_context m_ioService;
  boost::asio::ip::tcp::socket m_socket;
  std::string m_sendMsg; // 要发送的消息，本质为序列化后的请求
  char m_receiveBuf[1024];             // 接受的消息
  SelReturnData *m_pResData = nullptr; // 用于返回接受的数据

public:
  //!
  //! @brief 向指定端口发送消息以启动任务，并返回服务端结果
  //!
  //! @param ep 端口
  //! @param msg 消息
  //! @return SelReturnData
  //!
  static SelReturnData StartTask(boost::asio::ip::tcp::endpoint const &ep,
                                 std::string const &msg);
};
} // namespace VFAdapter

#endif